#ifndef Q_CORE_H_
#define Q_CORE_H_

#include "QSystemdetection.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <map>

#if defined(_MSC_VER) && (_MSC_VER >= 1600)
#pragma execution_character_set("utf-8")
#endif

using namespace std;

#if 0
#define PRINT_FUNC printf("%s: %s: %d\n",__FILE__, __func__, __LINE__);
#else
#define PRINT_FUNC 
#endif

typedef signed char qint8;         /* 8 bit signed */
typedef unsigned char quint8;      /* 8 bit unsigned */
typedef short qint16;              /* 16 bit signed */
typedef unsigned short quint16;    /* 16 bit unsigned */
typedef int qint32;                /* 32 bit signed */
typedef unsigned int quint32;      /* 32 bit unsigned */
#if defined(Q_OS_WIN) && !defined(Q_CC_GNU)
#  define Q_INT64_C(c) c ## i64    /* signed 64 bit constant */
#  define Q_UINT64_C(c) c ## ui64   /* unsigned 64 bit constant */
typedef __int64 qint64;            /* 64 bit signed */
typedef unsigned __int64 quint64;  /* 64 bit unsigned */
#else
#  define Q_INT64_C(c) static_cast<long long>(c ## LL)     /* signed 64 bit constant */
#  define Q_UINT64_C(c) static_cast<unsigned long long>(c ## ULL) /* unsigned 64 bit constant */
typedef long long qint64;           /* 64 bit signed */
typedef unsigned long long quint64; /* 64 bit unsigned */
#endif

typedef double qreal;

namespace Qt
{
    enum GlobalColor {
        color0,
        color1,
        black,
        white,
        darkGray,
        gray,
        lightGray,
        red,
        green,
        blue,
        cyan,
        magenta,
        yellow,
        darkRed,
        darkGreen,
        darkBlue,
        darkCyan,
        darkMagenta,
        darkYellow,
        transparent
    };

    enum AlignmentFlag {
        AlignLeft = 0x0001,
        AlignLeading = AlignLeft,
        AlignRight = 0x0002,
        AlignTrailing = AlignRight,
        AlignHCenter = 0x0004,
        AlignJustify = 0x0008,
        AlignAbsolute = 0x0010,
        AlignHorizontal_Mask = AlignLeft | AlignRight | AlignHCenter | AlignJustify | AlignAbsolute,

        AlignTop = 0x0020,
        AlignBottom = 0x0040,
        AlignVCenter = 0x0080,
        AlignBaseline = 0x0100,
        // Note that 0x100 will clash with Qt::TextSingleLine = 0x100 due to what the comment above
        // this enum declaration states. However, since Qt::AlignBaseline is only used by layouts,
        // it doesn't make sense to pass Qt::AlignBaseline to QPainter::drawText(), so there
        // shouldn't really be any ambiguity between the two overlapping enum values.
        AlignVertical_Mask = AlignTop | AlignBottom | AlignVCenter | AlignBaseline,

        AlignCenter = AlignVCenter | AlignHCenter
    };

    enum AspectRatioMode {
        IgnoreAspectRatio,
        KeepAspectRatio,
        KeepAspectRatioByExpanding
    };

    enum MouseButtons {
        NoButton = 0,
        LeftButton = 0x1,
        RightButton = 0x2,
        MidButton = 0x4,
    };

    enum CaseSensitivity{
        CaseInsensitive,
        CaseSensitive,
    };

}

template <typename T>
T qAbs(const T &t) { return t >= 0 ? t : -t; }

inline int qRound(double d)
{
    return d >= 0.0 ? int(d + 0.5) : int(d - double(int(d - 1)) + 0.5) + int(d - 1);
}
inline int qRound(float d)
{
    return d >= 0.0f ? int(d + 0.5f) : int(d - float(int(d - 1)) + 0.5f) + int(d - 1);
}

template <typename T>
const T &qMin(const T &a, const T &b) { return (a < b) ? a : b; }
template <typename T>
const T &qMax(const T &a, const T &b) { return (a < b) ? b : a; }
template <typename T>
const T &qBound(const T &min, const T &val, const T &max)
{
    return qMax(min, qMin(max, val));
}

static bool qFuzzyCompare(double p1, double p2);
static bool qFuzzyCompare(double p1, double p2)
{
    return (qAbs(p1 - p2) * 1000000000000. <= qMin(qAbs(p1), qAbs(p2)));
}

static bool qFuzzyCompare(float p1, float p2);
static bool qFuzzyCompare(float p1, float p2)
{
    return (qAbs(p1 - p2) * 100000.f <= qMin(qAbs(p1), qAbs(p2)));
}

/*!
\internal
*/
static bool qFuzzyIsNull(double d);
static bool qFuzzyIsNull(double d)
{
    return qAbs(d) <= 0.000000000001;
}

/*!
\internal
*/
static bool qFuzzyIsNull(float f);
static bool qFuzzyIsNull(float f)
{
    return qAbs(f) <= 0.00001f;
}

/*
This function tests a double for a null value. It doesn't
check whether the actual value is 0 or close to 0, but whether
it is binary 0, disregarding sign.
*/
static bool qIsNull(double d) ;
static bool qIsNull(double d)
{
    union U {
        double d;
        quint64 u;
    };
    U val;
    val.d = d;
    return (val.u & Q_UINT64_C(0x7fffffffffffffff)) == 0;
}

/*
This function tests a float for a null value. It doesn't
check whether the actual value is 0 or close to 0, but whether
it is binary 0, disregarding sign.
*/
static bool qIsNull(float f) ;
static bool qIsNull(float f)
{
    union U {
        float f;
        quint32 u;
    };
    U val;
    val.f = f;
    return (val.u & 0x7fffffff) == 0;
}

#if !defined(Q_ASSERT)
#define Q_ASSERT(cond) assert(cond)
#endif

#define qWarning printf

#define qSqrt sqrt
#define qSin sin
#define qCos cos

#define qAtan2 atan2
#define qAcos acos

#define Q_UNUSED(...)

#define Q_DISABLE_COPY(Class) \
    Class(const Class &); \
    Class &operator=(const Class &);

#ifndef M_2PI
#define M_2PI 6.28318530717958647692528676655900576
#endif

typedef struct _widget_t widget_t;
typedef struct _canvas_t canvas_t;
typedef struct _event_t event_t;
typedef struct _children_layouter_t children_layouter_t;

class QDebug
{
public:
    QDebug();
    ~QDebug();

    QDebug &operator<<(int i);
    QDebug &operator<<(double d);
    QDebug &operator<<(const char *text);
    QDebug &operator<<(void *ptr);
};
#define qDebug() QDebug()


//QSize
class QSize
{
public:
    QSize();
    QSize(int w, int h);

    bool isNull() const;
    bool isEmpty() const;
    bool isValid() const;

    int width() const;
    int height() const;
    void setWidth(int w);
    void setHeight(int h);
    void transpose();
    QSize transposed() const;

    void scale(int w, int h, Qt::AspectRatioMode mode);
    void scale(const QSize &s, Qt::AspectRatioMode mode);
    QSize scaled(int w, int h, Qt::AspectRatioMode mode) const;
    QSize scaled(const QSize &s, Qt::AspectRatioMode mode) const;

    QSize expandedTo(const QSize &) const;
    QSize boundedTo(const QSize &) const;

    int &rwidth();
    int &rheight();

    QSize &operator+=(const QSize &);
    QSize &operator-=(const QSize &);
    QSize &operator*=(qreal c);
    QSize &operator/=(qreal c);

    friend bool operator==(const QSize &, const QSize &);
    friend bool operator!=(const QSize &, const QSize &);
    friend const QSize operator+(const QSize &, const QSize &);
    friend const QSize operator-(const QSize &, const QSize &);
    friend const QSize operator*(const QSize &, qreal);
    friend const QSize operator*(qreal, const QSize &);
    friend const QSize operator/(const QSize &, qreal);

private:
    int wd;
    int ht;
};
const QSize operator*(const QSize &, qreal);
const QSize operator/(const QSize &, qreal);

//QColor
class QColor
{
public:
    QColor();
    QColor(Qt::GlobalColor color);
    QColor(int r, int g, int b, int a = 255);

    int alpha() const;
    void setAlpha(int alpha);

    qreal alphaF() const;
    void setAlphaF(qreal alpha);

    int red() const;
    int green() const;
    int blue() const;
    void setRed(int red);
    void setGreen(int green);
    void setBlue(int blue);

    quint32 rgb() const;
    quint32 rgba() const;

protected:
    union {
        quint32 rgba;
        struct {
            quint8 b;
            quint8 g;
            quint8 r;
            quint8 a;
        };
    }m_value;
};

//QPoint
class QPoint 
{
public:
    QPoint();
    QPoint(int x, int y);

    bool isNull() const;

    int x() const;
    int y() const;
    void setX(int x);
    void setY(int y);

    int manhattanLength() const;

    int &rx();
    int &ry();

    QPoint &operator+=(const QPoint &p);
    QPoint &operator-=(const QPoint &p);

    QPoint &operator*=(float factor);
    QPoint &operator*=(double factor);
    QPoint &operator*=(int factor);

    QPoint &operator/=(qreal divisor);

    static  int dotProduct(const QPoint &p1, const QPoint &p2)
    {
        return p1.xp * p2.xp + p1.yp * p2.yp;
    }
    friend bool operator==(const QPoint &, const QPoint &);
    friend bool operator!=(const QPoint &, const QPoint &);
    friend const QPoint operator+(const QPoint &, const QPoint &);
    friend const QPoint operator-(const QPoint &, const QPoint &);
    friend const QPoint operator*(const QPoint &, float);
    friend const QPoint operator*(float, const QPoint &);
    friend const QPoint operator*(const QPoint &, double);
    friend const QPoint operator*(double, const QPoint &);
    friend const QPoint operator*(const QPoint &, int);
    friend const QPoint operator*(int, const QPoint &);
    friend const QPoint operator+(const QPoint &);
    friend const QPoint operator-(const QPoint &);
    friend const QPoint operator/(const QPoint &, qreal);

protected:
    int xp;
    int yp;
};

class QPointF
{
public:
    QPointF();
    QPointF(const QPoint &p);
    QPointF(qreal xpos, qreal ypos);

    qreal manhattanLength() const;

    bool isNull() const;

    qreal x() const;
    qreal y() const;
    void setX(qreal x);
    void setY(qreal y);

    qreal &rx();
    qreal &ry();

    QPointF &operator+=(const QPointF &p);
    QPointF &operator-=(const QPointF &p);
    QPointF &operator*=(qreal c);
    QPointF &operator/=(qreal c);

    static qreal dotProduct(const QPointF &p1, const QPointF &p2)
    {
        return p1.xp * p2.xp + p1.yp * p2.yp;
    }

    friend bool operator==(const QPointF &, const QPointF &);
    friend bool operator!=(const QPointF &, const QPointF &);
    friend const QPointF operator+(const QPointF &, const QPointF &);
    friend const QPointF operator-(const QPointF &, const QPointF &);
    friend const QPointF operator*(qreal, const QPointF &);
    friend const QPointF operator*(const QPointF &, qreal);
    friend const QPointF operator+(const QPointF &);
    friend const QPointF operator-(const QPointF &);
    friend const QPointF operator/(const QPointF &, qreal);

    QPoint toPoint() const;

private:
    qreal xp;
    qreal yp;
};

class QRect
{
public:
    QRect() : x1(0), y1(0), x2(-1), y2(-1) {}
    QRect(const QPoint &topleft, const QPoint &bottomright);
    QRect(const QPoint &topleft, const QSize &size);
    QRect(int left, int top, int width, int height);

    bool isNull() const;
    bool isEmpty() const;
    bool isValid() const;

    int left() const;
    int top() const;
    int right() const;
    int bottom() const;
    QRect normalized() const;

    int x() const;
    int y() const;
    void setLeft(int pos);
    void setTop(int pos);
    void setRight(int pos);
    void setBottom(int pos);
    void setX(int x);
    void setY(int y);

    void setTopLeft(const QPoint &p);
    void setBottomRight(const QPoint &p);
    void setTopRight(const QPoint &p);
    void setBottomLeft(const QPoint &p);

    QPoint topLeft() const;
    QPoint bottomRight() const;
    QPoint topRight() const;
    QPoint bottomLeft() const;
    QPoint center() const;

    void moveLeft(int pos);
    void moveTop(int pos);
    void moveRight(int pos);
    void moveBottom(int pos);
    void moveTopLeft(const QPoint &p);
    void moveBottomRight(const QPoint &p);
    void moveTopRight(const QPoint &p);
    void moveBottomLeft(const QPoint &p);
    void moveCenter(const QPoint &p);

    void translate(int dx, int dy);
    void translate(const QPoint &p);
    QRect translated(int dx, int dy) const;
    QRect translated(const QPoint &p) const;

    void moveTo(int x, int t);
    void moveTo(const QPoint &p);

    void setRect(int x, int y, int w, int h);
    void getRect(int *x, int *y, int *w, int *h) const;

    void setCoords(int x1, int y1, int x2, int y2);
    void getCoords(int *x1, int *y1, int *x2, int *y2) const;

    void adjust(int x1, int y1, int x2, int y2);
    QRect adjusted(int x1, int y1, int x2, int y2) const;

    QSize size() const;
    int width() const;
    int height() const;
    void setWidth(int w);
    void setHeight(int h);
    void setSize(const QSize &s);

    QRect operator|(const QRect &r) const;
    QRect operator&(const QRect &r) const;
    QRect& operator|=(const QRect &r);
    QRect& operator&=(const QRect &r);

    bool contains(const QRect &r, bool proper = false) const;
    bool contains(const QPoint &p, bool proper = false) const;
    bool contains(int x, int y) const;
    bool contains(int x, int y, bool proper) const;
    QRect united(const QRect &other) const;
    QRect intersected(const QRect &other) const;
    bool intersects(const QRect &r) const;

    friend bool operator==(const QRect &, const QRect &);
    friend bool operator!=(const QRect &, const QRect &);

private:
    int x1;
    int y1;
    int x2;
    int y2;
};
QDebug &operator<<(QDebug &dbg, const QRect &rc);

template<class T>
class QVector
{
public:
    QVector() {};

    int indexOf(const T &t);
    void remove(int i);
    void removeAll(const T &t);

    inline int size() { return (int)m_vector.size();  }
    inline void clear() { m_vector.clear();  }

    inline T &at(int i) { return m_vector.at(i); }
    inline void append(const T &t) { m_vector.push_back(t); }

    inline void push_back(const T &t) { m_vector.push_back(t); }
    inline void pop_back() { m_vector.pop_back(); }

    inline T &operator[](int index) { return m_vector[index]; }
    inline QVector &operator <<(const T &t) { m_vector.push_back(t);  return *this;  }

protected:
    vector<T> m_vector;
};

template<class T>
int QVector<T>::indexOf(const T &t)
{
    for (size_t i = 0; i < m_vector.size(); i++)
    {
        if (m_vector[i] == t)
            return (int)i;
    }
    return -1;
}

template<class T>
void QVector<T>::remove(int i)
{
    m_vector.erase(m_vector.begin() + i);
}

template<class T>
void QVector<T>::removeAll(const T &t)
{
    for (size_t i = m_vector.size() - 1; i != -1; i--)
    {
        if (m_vector[i] == t)
            m_vector.erase(m_vector.begin() + i);
    }
}

//QMap
template<class Key,class T>
class QMap
{
public:
    QMap() {}

    void insert(const Key &key, const T &value) { m_map[key] = value; }
    bool contains(const Key &key) const { return m_map.find(key) != m_map.end(); }
    int count() const { return m_map.size(); }

    T &operator[](const Key &key) { return m_map.at(key); }

protected:
    std::map<Key, T> m_map;
};

class QString;
class QStringList : public QVector<QString>
{
public:
    QString join(const QString &sep);
};

//QString
class QString
{
public:
    enum SplitBehavior{
        KeepEmptyParts,
        SkipEmptyParts, 
    };

    static QString number(int value);
    static QString number(double value);

    QString();
    QString(const char *str);

    bool isEmpty() const;
    int size() const;

    QString mid(int start,int len = -1) const;
    QString toLower() const;
    QString toUpper() const;

    int toInt(bool *ok = NULL);
    double toDouble(bool *ok = NULL);

    QString &append(const QString &str);
    QString &append(const char *str);

    int compare(const QString &other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool endsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    QStringList split(const QString &sep, SplitBehavior behavior = KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    int indexOf(const QString &str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    int lastIndexOf(const QString &str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

    QString &insert(int position, const QString &str);
    void replace(const QString &before, QString after, Qt::CaseSensitivity cs = Qt::CaseSensitive);

    QString &sprintf(const char *cformat, ...);
    const char *c_str() const;
    
    bool operator==(const QString &other) const;
    bool operator!=(const QString &other) const;
    bool operator<(const QString &other) const;
    bool operator>(const QString &other) const;
    QString &operator+=(const QString &other);       

protected:
    friend QString operator+(const QString &s1, const QString &s2);

    string m_str;
};
QString operator+(const QString &s1, const QString &s2);
QDebug &operator<<(QDebug &dbg, const QString &str);

class QObject;
typedef void (QObject::*EventHandle)(void *param);

enum {
    SIG_Invaild,
    SIG_Clicked,
    SIG_ValueChange,
    SIG_TimeOut,

    SIG_USER = 10000,
};

class ObjectManager
{
public:
    void connect(QObject *sender, int signal, QObject *recv, EventHandle handle, int trans_signal);    
    void emit(QObject *sender, int signal, void *args);
    
    QObject *sender();    

protected:
    struct signalMap {        
        QObject *sender;
        int signal;
        QObject *receiver;
        EventHandle handle;
        int outSignal;
    };

    vector<signalMap> m_signalMap;
    QObject *m_sender;
};

//QMeta
class QMetaObject
{
public:
    QMetaObject(const char *name, QMetaObject *super);
    
    const QString &className() const;
    const QMetaObject *superClass() const;

protected:
    QString m_name;
    QMetaObject *m_super;
};

#define DECLARETION_META(name) \
    static QMetaObject ClassMeta; \
    virtual const QMetaObject *meta() const { return &ClassMeta; }
#define IMPLEMENT_META(name,super) \
    QMetaObject name::ClassMeta(#name,&super::ClassMeta);

//QVariant
class QVariant 
{
public:
    QVariant();
    QVariant(int i);
    QVariant(double d);
    QVariant(const QString &str);
    ~QVariant();

    int toInt() const;
    double toDouble() const;
    QString toString() const;
};

class QObject
{
public:    
    QObject(QObject *parent = nullptr);
    virtual ~QObject();
    
    DECLARETION_META(QObject)
    
    bool inherits(const QString &name) const;    
    QString objectName() const;
    void setObjectName(const QString &name);

    const QVariant &property(const char *name);
    void setProperty(const char *name, const QVariant &var);
    void deleteLater();

    void connect(QObject *sender, int signal, QObject *recv, EventHandle handle);
    void connect(QObject *sender, int signal, QObject *recv, int trans_signal);
    
    void emit(int signal, void *args);
    QObject *sender();

    QObject *parent();
    void setParent(QObject *object);

    QString tr(const QString &str);
    virtual void registEvent(EventHandle handle);

protected:
    virtual void registEventHandle(int type, EventHandle handle) {};
    virtual void onChildAdd(QObject *object);
    virtual void onChildRemove(QObject *object);

    QObject *m_parent;
    QVector<QObject*> m_childs;

private:
    Q_DISABLE_COPY(QObject);    

    QMap<QString,QVariant> m_propMap;
};

class QLine
{
public:
    QLine();
    QLine(const QPoint &pt1, const QPoint &pt2);
    QLine(int x1, int y1, int x2, int y2);

    bool isNull() const;

    QPoint p1() const;
    QPoint p2() const;

    int x1() const;
    int y1() const;

    int x2() const;
    int y2() const;

    int dx() const;
    int dy() const;

    void translate(const QPoint &p);
    void translate(int dx, int dy);

    QLine translated(const QPoint &p) const;
    QLine translated(int dx, int dy) const;

    void setP1(const QPoint &p1);
    void setP2(const QPoint &p2);
    void setPoints(const QPoint &p1, const QPoint &p2);
    void setLine(int x1, int y1, int x2, int y2);

    bool operator==(const QLine &d) const;
    bool operator!=(const QLine &d) const { return !(*this == d); }

private:
    QPoint pt1, pt2;
};

/*******************************************************************************
* class QLineF
*******************************************************************************/
class QLineF {
public:

    enum IntersectType { NoIntersection, BoundedIntersection, UnboundedIntersection };

    QLineF();
    QLineF(const QPointF &pt1, const QPointF &pt2);
    QLineF(qreal x1, qreal y1, qreal x2, qreal y2);
    QLineF(const QLine &line) : pt1(line.p1()), pt2(line.p2()) { }

    static QLineF fromPolar(qreal length, qreal angle);

    bool isNull() const;

    QPointF p1() const;
    QPointF p2() const;

    qreal x1() const;
    qreal y1() const;

    qreal x2() const;
    qreal y2() const;

    qreal dx() const;
    qreal dy() const;

    qreal length() const;
    void setLength(qreal len);

    qreal angle() const;
    void setAngle(qreal angle);

    qreal angleTo(const QLineF &l) const;

    QLineF unitVector() const;
    QLineF normalVector() const;

    // ### Qt 6: rename intersects() or intersection() and rename IntersectType IntersectionType
    IntersectType intersect(const QLineF &l, QPointF *intersectionPoint) const;

    qreal angle(const QLineF &l) const;

    QPointF pointAt(qreal t) const;
    void translate(const QPointF &p);
    void translate(qreal dx, qreal dy);

    QLineF translated(const QPointF &p) const;
    QLineF translated(qreal dx, qreal dy) const;

    void setP1(const QPointF &p1);
    void setP2(const QPointF &p2);
    void setPoints(const QPointF &p1, const QPointF &p2);
    void setLine(qreal x1, qreal y1, qreal x2, qreal y2);

    bool operator==(const QLineF &d) const;
    bool operator!=(const QLineF &d) const { return !(*this == d); }

    QLine toLine() const;

private:
    QPointF pt1, pt2;
};


//QTimer
class QTimer : public QObject
{
public:
    QTimer(QObject *object);

    DECLARETION_META(QTimer)

    void start();
    void start(int ms);
    void stop();
    bool isActive();

    bool isSingleShot();
    void setSingleShot(bool flag);    

    int interval();
    void setInterval(int ms);

protected:
    int m_interval;
    quint32 m_timeId;
    bool m_single;
};

class QTime
{
public:
};

class QDateTime
{
public:
};


#endif // ! Q_CORE_H_
